﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace Framework
{
    internal class LogItem
    {
        public int level;
        public DateTime Date;
        public int FrameCount;
        public string Message;
    }
    public class DebugLogger : ILogger
    {
        private Queue<LogItem> _list = new Queue<LogItem>();
        private Queue<LogItem> _pool = new Queue<LogItem>(100);
        private StringBuilder StringBuilder = new StringBuilder();
        private LogItem GetLogItem()
        {
            lock (_pool)
            {
                if (_pool.Count > 0)
                {
                    return _pool.Dequeue();
                }
                return new LogItem();
            }
        }
        private void log(int level, string msg)
        {
            var item = GetLogItem();
            item.level = level;
            item.Message = msg;
            item.Date = DateTime.Now;
            item.FrameCount = UnityEngine.Time.frameCount;
            if (_list.Count > 1000)
            {
                return;
            }
            bool isMainThread = SynchronizationContext.Current == null;
            if (isMainThread)
            {
                execute(item);
            }
            else
            {
                lock (_list)
                {
                    _list.Enqueue(item);
                }
            }
        }
        public void LogErrorFormat(string format, params object[] args)
        {
            log(4, string.Format(format, args));
        }
        public void LogError(object message)
        {
            log(4, message.ToString());
        }
        public void LogFormat(string format, params object[] args)
        {
            log(1, string.Format(format, args));
        }
        public void Log(object message)
        {
            log(1, message.ToString());
        }
        public void LogWarning(object message)
        {
            log(2, message.ToString());
        }
        public void LogWarningFormat(string format, params object[] args)
        {
            log(2, string.Format(format, args));
        }

        public void LogException(Exception exception)
        {
            log(8, exception.ToString());
        }
        private const string str1 = " - ";
        private const string str2 = " ";
        private void execute(LogItem item)
        {
            StringBuilder.Append(item.Date.ToString("HH:mm:ss"));
            StringBuilder.Append(str1);
            StringBuilder.Append(UnityEngine.Time.frameCount);
            StringBuilder.Append(str2);
            StringBuilder.Append(item.Message);
            string value = StringBuilder.ToString();
            StringBuilder.Clear();

            if (item.level == 1)
            {
                UnityEngine.Debug.Log(value);
            }
            else if (item.level == 2)
            {
                UnityEngine.Debug.LogWarning(value);
            }
            else if (item.level == 4)
            {
                UnityEngine.Debug.LogError(value);
            }
            else if (item.level == 8)
            {
                UnityEngine.Debug.LogError(value);
            }
            _pool.Enqueue(item);
        }
        public void Update()
        {
            if (_list.Count < 1)
            {
                return;
            }
            lock (_list)
            {
                lock (_pool)
                {
                    while (_list.Count > 0)
                    {
                        var item = _list.Dequeue();
                        _pool.Enqueue(item);
                        execute(item);
                    }
                }

            }
        }
    }
}
